package com.flyqiu.flow.core.impl;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import com.flyqiu.common.tools.FlyQiuStreamTools;
import com.flyqiu.common.tools.StringTools;
import com.flyqiu.common.user.FlyQiuUser;
import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.service.IdentityLinkService;
import com.flyqiu.flow.api.service.hi.HiIdentityLinkService;
import com.flyqiu.flow.api.service.ru.RuIdentityLinkService;
import com.flyqiu.flow.model.entity.hi.ProcHiIdentityLink;
import com.flyqiu.flow.model.entity.ru.ProcRuIdentityLink;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class IdentityLinkServiceImpl implements IdentityLinkService {
    private final RuIdentityLinkService ruIdentityLinkService;
    private final HiIdentityLinkService hiIdentityLinkService;

    public IdentityLinkServiceImpl(FlyQiuFlowGlobalContext globalContext, RuIdentityLinkService ruIdentityLinkService, HiIdentityLinkService hiIdentityLinkService) {
        this.ruIdentityLinkService = ruIdentityLinkService;
        this.hiIdentityLinkService = hiIdentityLinkService;
    }

    @Override
    public void actAdd(String procInstId, String actId, String actInstId, String type, Collection<? extends FlyQiuUser> users) {
        if (users == null || users.isEmpty()) return;
        if (StringTools.isAllBlank(procInstId)) {
            throw new RuntimeException("procInstId cannot be null or empty");
        }
        if (StringTools.isAllBlank(actId)) {
            throw new RuntimeException("actId cannot be null or empty");
        }
        if (StringTools.isAllBlank(type)) {
            throw new RuntimeException("type cannot be null or empty");
        }
        Set<ProcRuIdentityLink> links = users.stream().filter(e -> StringTools.isNotBlank(e.getUniqueKey())).filter(FlyQiuStreamTools.distinctByKey(FlyQiuUser::getUniqueKey)).map(e -> ProcRuIdentityLink.create(e, procInstId, actId, actInstId, type)).collect(Collectors.toSet());
        LambdaQueryWrapper<ProcRuIdentityLink> oldLinkQuery = new LambdaQueryWrapper<>();
        oldLinkQuery.eq(ProcRuIdentityLink::getProcInstId, procInstId);
        oldLinkQuery.eq(ProcRuIdentityLink::getActId, actId);
        oldLinkQuery.eq(StringTools.isNotBlank(actInstId), ProcRuIdentityLink::getActInstId, actInstId);
        oldLinkQuery.eq(ProcRuIdentityLink::getType, type);
        Set<String> oldLinks = getRuIdentityLinks(oldLinkQuery).stream().map(ProcRuIdentityLink::getUserUniqueKey).collect(Collectors.toSet());
        if (oldLinks.isEmpty()) {
            Db.saveBatch(links);
            return;
        }
        links = links.stream().filter(e -> !oldLinks.contains(e.getUserUniqueKey())).collect(Collectors.toSet());
        if (links.isEmpty()) return;
        Db.saveBatch(links);
    }

    @Override
    public void add(Collection<ProcRuIdentityLink> links) {
        FlyQiuCollectionTools.iterator(links, (item) -> {
            if (StringTools.isAllBlank(item.getProcInstId())) {
                throw new RuntimeException("ProcRuIdentityLink procInstId  cannot be null or empty");
            }
            if (StringTools.isAllBlank(item.getActId())) {
                throw new RuntimeException("ProcRuIdentityLink actId  cannot be null or empty");
            }
            if (StringTools.isAllBlank(item.getUserId())) {
                throw new RuntimeException("ProcRuIdentityLink userId  cannot be null or empty");
            }

        });
        Db.saveBatch(links);

    }

    @Override
    public void moveToHistory(String procInstId, String actId) {
        LambdaQueryWrapper<ProcRuIdentityLink> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ProcRuIdentityLink::getProcInstId, procInstId);
        lambdaQueryWrapper.eq(StringTools.isNotBlank(actId), ProcRuIdentityLink::getActId, actId);
        List<ProcRuIdentityLink> ruIdentityLinks = getRuIdentityLinks(lambdaQueryWrapper);
        if (ruIdentityLinks == null || ruIdentityLinks.isEmpty()) {
            return;
        }
        moveToHistory(ruIdentityLinks);
        ruIdentityLinkService.remove(lambdaQueryWrapper);
    }


    private void moveToHistory(List<ProcRuIdentityLink> links) {
        if (links.isEmpty()) return;
        List<ProcHiIdentityLink> list = JSONArray.from(links).toList(ProcHiIdentityLink.class);
        hiIdentityLinkService.saveBatch(list);

    }

    @Override
    public void deleteRuIdentityLink(LambdaQueryWrapper<ProcRuIdentityLink> queryWrapper) {
        ruIdentityLinkService.remove(queryWrapper);
    }

    @Override
    public List<ProcRuIdentityLink> getRuIdentityLinks(LambdaQueryWrapper<ProcRuIdentityLink> queryWrapper) {
        return ruIdentityLinkService.list(queryWrapper);
    }

    @Override
    public List<ProcHiIdentityLink> getHiIdentityLinks(LambdaQueryWrapper<ProcHiIdentityLink> queryWrapper) {
        return hiIdentityLinkService.list(queryWrapper);
    }

    @Override
    public void deleteHiIdentityLink(LambdaQueryWrapper<ProcHiIdentityLink> queryWrapper) {
        hiIdentityLinkService.remove(queryWrapper);
    }
}
